/*
 * CFileConverter.cpp
 *
 *  Created on: 2017年3月15日
 *      Author: chuanjiang.zh
 */

#include "CFileConverter.h"
#include "DateTime.h"


CFileConverter::CFileConverter():
	m_state(UMEDIA_CONVERTER_CLOSED),
	m_curTs(),
	m_percent(),
	m_startTs(),
	m_sink(),
	m_id(),
	m_convStartTime(),
	m_convElapse()
{

}

CFileConverter::~CFileConverter()
{
	close();
}

int CFileConverter::open(const char* inputPath, const char* outputPath)
{
	if (!inputPath || !outputPath)
	{
		return EINVAL;
	}

	m_reader.reset(UniMediaReader::create(inputPath), UniMediaReader::destroy);
	m_writer.reset(UniMediaWriter::create(outputPath), UniMediaWriter::destroy);

	if (!m_reader || !m_writer)
	{
		return EINVAL;
	}

	m_inputPath = inputPath;
	m_outputPath = outputPath;

	m_convStartTime = comn::DateTime::getTime();

	int ret = m_reader->open(inputPath, "");
	if (ret != 0)
	{
		return ret;
	}

	m_reader->getFormat(m_format);

	setState(UMEDIA_CONVERTER_OPENING);

	bool done = m_writer->open(outputPath, m_format);
	if (done)
	{
		m_curTs = 0;
		m_percent = 0.0;
		m_startTs = 0;
		setState(UMEDIA_CONVERTER_OPENED);
	}
	else
	{
		closeInput();

		m_convElapse = comn::DateTime::getTime() - m_convStartTime;

		setState(UMEDIA_CONVERTER_ERROR);
	}

	return done ? 0 : EFAULT;
}

/**
 * 关闭
 */
void CFileConverter::close()
{
	if (isRunning())
	{
		comn::Thread::stop();
	}

	closeInput();
}

/**
 * 是否打开
 * @return
 */
bool CFileConverter::isOpen()
{
	if (isRunning())
	{
		return true;
	}

	std::lock_guard< std::mutex> lock(m_fileMutex);
	return ( m_reader && m_reader->isOpen());
}

/**
 * 获取输入的媒体格式
 * @param fmt
 * @return
 */
bool CFileConverter::getFormat(UMediaFormat& fmt)
{
	if (!m_format.isValid())
	{
		return false;
	}

	fmt = m_format;
	return true;
}

/**
 * 获取输入的媒体时长
 * 单位为毫秒
 * @return
 */
int CFileConverter::getDuration()
{
	return m_format.m_duration;
}

/**
 * 开始转换
 * @return
 */
int CFileConverter::start()
{
	if (isRunning())
	{
		return 0;
	}

	bool done = comn::Thread::start();
	return done ? 0: EFAULT;
}

/**
 * 停止转换
 */
void CFileConverter::stop()
{
	if (isRunning())
	{
		comn::Thread::tryStop();
	}
}

/**
 * 获取转换状态 @see ConvertState
 * @return
 */
int CFileConverter::getState()
{
	return m_state;
}

/**
 * 获取输入文件路径
 * @return
 */
const char* CFileConverter::getInput()
{
	return m_inputPath.c_str();
}

/**
 * 获取输出文件路径
 * @return
 */
const char* CFileConverter::getOutput()
{
	return m_outputPath.c_str();
}

/**
 * 获取当前媒体时间
 * @return
 */
int64_t CFileConverter::getTime()
{
	return m_curTs;
}

/**
 * 获取当前转换进度
 * @return
 */
double CFileConverter::getPos()
{
	return m_percent;
}

/**
 * 设置回调
 * 在Open之前调用
 * @param sink
 */
void CFileConverter::setSink(UMediaFileConverterSink* sink)
{
	std::lock_guard< std::mutex> lock(m_fileMutex);
	m_sink = sink;
}

int CFileConverter::run()
{
	int64_t count = 0;

	while (!m_canExit)
	{
		UMediaPacket packet;
		int ret = m_reader->read(packet);
		if (ret != 0)
		{
			m_writer->close();
			m_writer.reset();

			closeInput();

			m_convElapse = comn::DateTime::getTime() - m_convStartTime;

			setState(UMEDIA_CONVERTER_END);
			break;
		}

		m_writer->write(packet);

		count++;

		if (m_format.hasVideo())
		{
			if (packet.isVideo())
			{
				m_curTs = packet.dts();

				if (m_format.m_duration > 0)
				{
					m_percent = (double)m_curTs / 1000 / m_format.m_duration;
				}

				if (count == 1)
				{
					m_startTs = packet.dts();
				}

				if (packet.isKey())
				{
					fireState();
				}
			}
			else
			{
				continue;
			}
		}
		else
		{
			m_curTs = packet.dts();

			if (m_format.m_duration > 0)
			{
				m_percent = (double)m_curTs / 1000 / m_format.m_duration;
			}
			
			if (count == 1)
			{
				m_startTs = packet.dts();
			}

			if ((count % 25) == 0)
			{
				fireState();
			}
		}
	}

	if (m_writer)
	{
		m_writer->close();
		m_writer.reset();
	}

	return 0;
}

void CFileConverter::closeInput()
{
	std::lock_guard< std::mutex> lock(m_fileMutex);
	if (m_reader)
	{
		m_reader->close();
	}

	m_reader.reset();
}

void CFileConverter::setState(UMediaFileConverterState state)
{
	m_state = state;

	fireState();
}

void CFileConverter::fireState()
{
	if (m_sink)
	{
		m_sink->onConvert(this, (int)m_state, m_curTs, m_percent);
	}
}

int64_t CFileConverter::setId(int64_t id)
{
	int64_t prev = m_id;
	m_id = id;
	return prev;
}

int64_t CFileConverter::getId()
{
	return m_id;
}

int64_t CFileConverter::getStartTime()
{
	return m_convStartTime;
}

int64_t CFileConverter::getConvertElapse()
{
	if (m_convElapse <= 0)
	{
		return comn::DateTime::getTime() - m_convStartTime;
	}

	return m_convElapse;
}

int64_t CFileConverter::getConvertDuration()
{
	return (m_curTs - m_startTs) / 1000;
}